﻿#include "Libraries/FileLibrary.h"

EOperationResult UFileLibrary::GetOperationResult(bool InValue)
{
	return InValue ? EOperationResult::Success : EOperationResult::Failure;
}

bool UFileLibrary::DirectoryExists(const FString& DirectoryPath)
{
	IPlatformFile& FileManager = FPlatformFileManager::Get().GetPlatformFile();
	return FileManager.DirectoryExists(*DirectoryPath);
}

EOperationResult UFileLibrary::DirectoryCreate(const FString& DirectoryPath, bool bOverwriteAllExisting)
{
	IPlatformFile& FileManager = FPlatformFileManager::Get().GetPlatformFile();
	if (!DirectoryExists(DirectoryPath)) return GetOperationResult(FileManager.CreateDirectory(*DirectoryPath));
	else if (bOverwriteAllExisting)
		if (DirectoryDeleteRecursively(DirectoryPath) == EOperationResult::Success) return GetOperationResult(FileManager.CreateDirectory(*DirectoryPath));
		else return EOperationResult::Failure;
	return EOperationResult::Exist;
}

EOperationResult UFileLibrary::DirectoryCreateTree(const FString& DirectoryPath, bool bOverwriteAllExisting)
{
	IPlatformFile& FileManager = FPlatformFileManager::Get().GetPlatformFile();
	if (!DirectoryExists(DirectoryPath)) return GetOperationResult(FileManager.CreateDirectoryTree(*DirectoryPath));
	else if (bOverwriteAllExisting)
		if (DirectoryDeleteRecursively(DirectoryPath) == EOperationResult::Success) return GetOperationResult(FileManager.CreateDirectoryTree(*DirectoryPath));
		else return EOperationResult::Failure;

	return EOperationResult::Exist;
}

EOperationResult UFileLibrary::DirectoryDelete(const FString& DirectoryPath)
{
	if (DirectoryExists(DirectoryPath))
	{
		IPlatformFile& FileManager = FPlatformFileManager::Get().GetPlatformFile();
		return GetOperationResult(FileManager.DeleteDirectory(*DirectoryPath));
	}
	return EOperationResult::NotExist;
}

EOperationResult UFileLibrary::DirectoryDeleteRecursively(const FString& DirectoryPath)
{
	if (DirectoryExists(DirectoryPath))
	{
		IPlatformFile& FileManager = FPlatformFileManager::Get().GetPlatformFile();
		return GetOperationResult(FileManager.DeleteDirectoryRecursively(*DirectoryPath));
	}
	return EOperationResult::NotExist;
}

TArray<FString> UFileLibrary::DirectoryIterate(const FString& DirectoryPath, bool IncludeDirectory, bool IncludeFile)
{
	if (!DirectoryExists(DirectoryPath))
	{
		return TArray<FString>();
	}
	struct DirectoryVisitor : public IPlatformFile::FDirectoryVisitor
	{
		DirectoryVisitor(bool IncludeDirectory, bool IncludeFile): InIncludeDirectory(IncludeDirectory), InIncludeFile(IncludeFile) {}
		//This function is called for every file or directory it finds.
		bool Visit(const TCHAR* FilenameOrDirectory, bool bIsDirectory) override
		{
			bool Result;
			if (InIncludeDirectory && bIsDirectory) Result = true;
			else if (InIncludeFile && !bIsDirectory) Result = true;
			else Result = false;
			if (Result) DirectoryPaths.Push(FilenameOrDirectory);
			return true;
		}

		bool InIncludeDirectory;
		bool InIncludeFile;
		TArray<FString> DirectoryPaths;
	};
	DirectoryVisitor Visitor(IncludeDirectory, IncludeFile);
	IPlatformFile& FileManager = FPlatformFileManager::Get().GetPlatformFile();
	FileManager.IterateDirectory(*DirectoryPath, Visitor);
	return Visitor.DirectoryPaths;
}

TArray<FString> UFileLibrary::DirectoryIterateRecursively(const FString& DirectoryPath, bool IncludeDirectory, bool IncludeFile)
{
	if (!DirectoryExists(DirectoryPath))
	{
		return TArray<FString>();
	}
	struct DirectoryVisitor : public IPlatformFile::FDirectoryVisitor
	{
		DirectoryVisitor(bool IncludeDirectory, bool IncludeFile): InIncludeDirectory(IncludeDirectory), InIncludeFile(IncludeFile) {}
		//This function is called for every file or directory it finds.
		bool Visit(const TCHAR* FilenameOrDirectory, bool bIsDirectory) override
		{
			bool Result;
			if (InIncludeDirectory && bIsDirectory) Result = true;
			else if (InIncludeFile && !bIsDirectory) Result = true;
			else Result = false;
			if (Result) DirectoryPaths.Push(FilenameOrDirectory);
			return true;
		}

		bool InIncludeDirectory;
		bool InIncludeFile;
		TArray<FString> DirectoryPaths;
	};
	DirectoryVisitor Visitor(IncludeDirectory, IncludeFile);
	IPlatformFile& FileManager = FPlatformFileManager::Get().GetPlatformFile();
	FileManager.IterateDirectoryRecursively(*DirectoryPath, Visitor);
	return Visitor.DirectoryPaths;
}

EOperationResult UFileLibrary::DirectoryCopyTree(const FString& Destination, const FString& source, bool bOverwriteAllExisting)
{
	if (Destination == source) return EOperationResult::Success;
	if (DirectoryExists(source))
	{
		IPlatformFile& FileManager = FPlatformFileManager::Get().GetPlatformFile();
		if (DirectoryExists(Destination) && !bOverwriteAllExisting) return EOperationResult::Exist;
		else return GetOperationResult(FileManager.CopyDirectoryTree(*Destination, *source, bOverwriteAllExisting));
	}
	return EOperationResult::NotExist;
}

EOperationResult UFileLibrary::DirectoryMoveTree(const FString& Destination, const FString& source, bool bOverwriteAllExisting)
{
	TArray<FString> SpliteString;
	source.ParseIntoArray(SpliteString, TEXT("/"));
	FString TargetPath = Destination + "/" + SpliteString.Last();
	if (TargetPath == source) return EOperationResult::Success;
	if (DirectoryExists(source))
	{
		if (DirectoryExists(TargetPath) && !bOverwriteAllExisting) return EOperationResult::Exist;
		else if (DirectoryCopyTree(TargetPath, source, bOverwriteAllExisting) == EOperationResult::Success) return DirectoryDeleteRecursively(source);
	}
	return EOperationResult::NotExist;
}

bool UFileLibrary::FileExist(const FString& FilePath)
{
	IPlatformFile& FileManager = FPlatformFileManager::Get().GetPlatformFile();
	return FileManager.FileExists(*FilePath);
}

EOperationResult UFileLibrary::FileCopy(const FString& Destination, const FString& source, bool bOverwriteAllExisting)
{
	if (Destination == source) return EOperationResult::Success;
	IPlatformFile& FileManager = FPlatformFileManager::Get().GetPlatformFile();
	if (FileExist(source)) return GetOperationResult(FileManager.CopyFile(*Destination, *source, EPlatformFileRead::None, EPlatformFileWrite::None));
	else if (FileExist(Destination) && !bOverwriteAllExisting) return EOperationResult::Exist;
	else if (bOverwriteAllExisting)
		if (FileDelete(Destination) == EOperationResult::Success) return GetOperationResult(FileManager.CopyFile(*Destination, *source, EPlatformFileRead::None, EPlatformFileWrite::None));
		else return EOperationResult::Failure;
	return EOperationResult::NotExist;
}

EOperationResult UFileLibrary::FileDelete(const FString& FilePath)
{
	if (FileExist(FilePath))
	{
		IPlatformFile& FileManager = FPlatformFileManager::Get().GetPlatformFile();
		return GetOperationResult(FileManager.DeleteFile(*FilePath));
	}
	return EOperationResult::NotExist;
}

int UFileLibrary::FileSize(const FString& FilePath)
{
	if (FileExist(FilePath))
	{
		IPlatformFile& FileManager = FPlatformFileManager::Get().GetPlatformFile();
		return FileManager.FileSize(*FilePath);
	}
	return -1;
}

EOperationResult UFileLibrary::FileMove(const FString& Destination, const FString& source, bool bOverwriteAllExisting)
{
	TArray<FString> SpliteString;
	source.ParseIntoArray(SpliteString, TEXT("/"));
	FString TargetPath = Destination + "/" + SpliteString.Last();
	if (TargetPath == source) return EOperationResult::Success;
	if (FileExist(source))
	{
		IPlatformFile& FileManager = FPlatformFileManager::Get().GetPlatformFile();
		if (FileExist(TargetPath) && !bOverwriteAllExisting) return EOperationResult::Exist;
		return GetOperationResult(FileManager.MoveFile(*TargetPath, *source));
	}
	return EOperationResult::NotExist;
}
